#include "netcore.h"


NetCore::NetCore()
{
}

NetCore::~NetCore()
{
}

void NetCore::config(int port)
{
    this->port = port;
}

void NetCore::start()
{
    //初始化网络，开启监听
    tcpServer = new QTcpServer(this);
    if(port > 0 && port <= 65535)
    {
        if(tcpServer->listen(QHostAddress::Any, port))
        {
            // 绑定新连接信号
            connect(tcpServer, &QTcpServer::newConnection, this, &NetCore::on_tcp_connect);
            // 绑定accept错误信号
            connect(tcpServer, &QTcpServer::acceptError, this, &NetCore::on_tcp_accept_error);
        }
        else
        {
            emit this->sigError(ERR_NET_PORT,  "程序端口被占用，监听失败");
        }
    }else
    {
        emit this->sigError(ERR_FORMAT, "端口范围必须在1-65535");
    }
}

void NetCore::stop()
{
    // 停止监听
    if(tcpServer && tcpServer->isListening())
    {
        tcpServer->close();
    }
    // 删除网络连接列表
    foreach(MyTcpSocket * myTcpSocket, myTcpSocketList)
    {
        delete myTcpSocket;// 删除对象
    }
    myTcpSocketList.clear();

}

void NetCore::on_tcp_connect()
{
    MyTcpSocket * mytcpsocket = new MyTcpSocket(tcpServer->nextPendingConnection());

    // 发送信号通知上层有新客户端接入
    emit this->sigClient(CLI_NEW, mytcpsocket);

    // 发送计算网络延时信号
    delayRequest(mytcpsocket);

    // 绑定数据可读信号
    connect(mytcpsocket->getTcpSocket(), &QTcpSocket::readyRead, this, &NetCore::on_tcp_read);
    // 绑定断开连接信号
    connect(mytcpsocket->getTcpSocket(), &QTcpSocket::disconnected, this, &NetCore::on_tcp_disconnect);
    // 绑定接收到完整数据包信号
    connect(mytcpsocket, &MyTcpSocket::sigPkgReady, this, &NetCore::on_pkg_ready);
    // 添加到客户端列表
    myTcpSocketList.append(mytcpsocket);

    qDebug() << "现有客户端个数" << myTcpSocketList.size();
}

void NetCore::on_tcp_disconnect()
{
    QTcpSocket *tmpTcpSocket = (QTcpSocket*)sender();
    qDebug() << "断开连接" << tmpTcpSocket->socketDescriptor() << tmpTcpSocket->peerAddress().toString() << tmpTcpSocket->peerName();

    // 找到socket列表中对应项目删除
    foreach(MyTcpSocket * myTcpSocket, myTcpSocketList)
    {
        if(myTcpSocket->getPeerAddr() == tmpTcpSocket->peerAddress().toString() &&
                myTcpSocket->getPeerName() == tmpTcpSocket->peerName() &&
                myTcpSocket->getTcpSocket()->state() != QAbstractSocket::ConnectedState)
        {
            // 通知上层UI删除该客户端
            emit this->sigClient(CLI_DEL, myTcpSocket);

            // 从客户端列表删除，并delete对象
            qDebug() << "删除socket连接" << myTcpSocket->getTcpSocket()->peerAddress();
            myTcpSocketList.removeOne(myTcpSocket);// 从QList中删除
            myTcpSocket->getTcpSocket()->deleteLater(); //删除socket
            delete myTcpSocket;// 删除对象
            myTcpSocket = nullptr;
            break;
        }
    }

    qDebug() << "现有客户端个数" << myTcpSocketList.size();
}

void NetCore::on_tcp_accept_error(QAbstractSocket::SocketError socketError)
{
    emit this->sigError(ERR_NET_ACCEPT, QString("ACCEPT错误：代码 %1").arg(QString::number(socketError)));
}

void NetCore::on_pkg_ready(QByteArray data, MyTcpSocket * myTcpSocket)
{
    qDebug() << "收到数据" << data.length();


    // 这里要区分数据是配置数据还是屏幕位图流数据
    // 为了提高效率，判定首两位字符就行
    // 配置信息 -- 首字母必须为{
    // 位图流数据 -- 首两位字符为x,y坐标，必须为数字

    // 配置信息
    if(data.at(0) == '{')
    {
        QJsonDocument jsonDocument = QJsonDocument::fromJson(data);
        if(!jsonDocument.isNull())
        {
            QJsonObject rootObject = jsonDocument.object();
            if(!rootObject.value("cmd").isNull() && rootObject.value("cmd") == "delay")
            {
                QJsonObject jsonObject = rootObject.value("data").toObject();

                if (!jsonObject.value("send").isNull() && !jsonObject.value("recv").isNull())
                {
                    qint64 send = jsonObject.value("send").toString().toLongLong();
                    qint64 recv = jsonObject.value("recv").toString().toLongLong();
                    int delayTime = (int) (recv - send);
                    // 寻找客户端，将接收数据写入客户端的解包函数
                    foreach(MyTcpSocket * tmpTcpSocket, myTcpSocketList)
                    {
                        if(myTcpSocket == tmpTcpSocket)
                        {
                            myTcpSocket->setDelay(delayTime);
                            // 通知上层UI，修正客户端信息
                            emit this->sigClient(CLI_UPDATE, myTcpSocket);

                            break;
                        }
                    }
                }
            }
        }
    }
    // 位图流数据
    else if((data.at(0) >=0 && data.at(0) < 128) && (data.at(1) >=0 && data.at(1) < 128))
    {
        emit this->sigScData(myTcpSocket, data.at(0), data.at(1), data.right(data.length() - 2));
    }
    else
    {

    }
}

void NetCore::on_tcp_read()
{
    QTcpSocket * tmpTcpSocket = (QTcpSocket*)sender();

    // 寻找客户端，将接收数据写入客户端的解包函数
    foreach(MyTcpSocket * myTcpSocket, myTcpSocketList)
    {
        if(myTcpSocket->getDescriptor() == tmpTcpSocket->socketDescriptor())
        {
            myTcpSocket->unPkg(tmpTcpSocket->readAll());
            break;
        }
    }
}


// ****************** 以下是功能函数 ***********************

void NetCore::delayRequest(MyTcpSocket * myTcpSocket)
{
    if(myTcpSocket)
    {
        qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
        QJsonObject rootObject;
        QJsonObject itemObject;
        itemObject.insert("send", QString("%1").arg(timestamp));
        itemObject.insert("recv", "0");
        rootObject.insert("cmd", "delay");
        rootObject.insert("data", itemObject);
        QJsonDocument doc(rootObject);
        qDebug() << doc.toJson(QJsonDocument::Compact);
        myTcpSocket->send(doc.toJson(QJsonDocument::Compact));
    }else
    {
        emit this->sigError(ERR_NET_SOCKET, "客户端连接存在问题");
    }
}

void NetCore::scSigRequest(MyTcpSocket * myTcpSocket, int code)
{
    if(myTcpSocket)
    {
        QJsonObject rootObject;
        QJsonObject itemObject;
        itemObject.insert("code", code);
        rootObject.insert("cmd", "scsig");
        rootObject.insert("data", itemObject);
        QJsonDocument doc(rootObject);
        qDebug() << doc.toJson(QJsonDocument::Compact);
        myTcpSocket->send(doc.toJson(QJsonDocument::Compact));
    }else
    {
        emit this->sigError(ERR_NET_SOCKET, "客户端连接存在问题");
    }
}

void NetCore::scConfigRequest(MyTcpSocket *myTcpSocket, Config * config)
{
    if(myTcpSocket)
    {
        QJsonObject rootObject;
        QJsonObject jObject;
        jObject.insert("width", config->scWidth);
        jObject.insert("height", config->scHeight);
        jObject.insert("x", config->indexX);
        jObject.insert("y", config->indexY);
        jObject.insert("bit", config->bit);
        jObject.insert("fps", config->fps);
        rootObject.insert("cmd", "config");
        rootObject.insert("data", jObject);
        QJsonDocument doc(rootObject);
        qDebug() << doc.toJson(QJsonDocument::Compact);
        myTcpSocket->send(doc.toJson(QJsonDocument::Compact));
    }else
    {
        emit this->sigError(ERR_NET_SOCKET, "客户端连接存在问题");
    }
}

MyTcpSocket * NetCore::findTcpSocket(int descriptor)
{
    MyTcpSocket * tmpTcpSocket = nullptr;
    foreach(MyTcpSocket * myTcpSocket, myTcpSocketList)
    {
        if(myTcpSocket->getDescriptor() == descriptor)
        {
            tmpTcpSocket = myTcpSocket;
            break;
        }
    }
    return tmpTcpSocket;
}
